﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Security.Cryptography;
using System.Net;
using System.Net.NetworkInformation;
using System.Web;
using System.Web.UI;
using System.Xml;

namespace ExtendedWorkFlow
{

    public class Functions
    {

        /// <summary>
        /// Get KeyValuePair of value in standard querystring format
        /// </summary>
        /// <param name="Value">String to break</param>
        /// <returns>KeyValuePair<string, string> of value</returns>
        public static KeyValuePair<string, string>[] GetKeyValuePair(string Value)
        {
            List<KeyValuePair<string, string>> colParameters = new List<KeyValuePair<string,string>>();
            foreach (string strParameter in Value.Split("&".ToCharArray()))
            {
                string[] strKeyValue = strParameter.Split("=".ToCharArray());

                if (strKeyValue.GetUpperBound(0) >= 1)
                    colParameters.Add(new KeyValuePair<string,string>(HttpUtility.UrlDecode(strKeyValue[0]), HttpUtility.UrlDecode(strKeyValue[1])));
                else
                    colParameters.Add(new KeyValuePair<string, string>(HttpUtility.UrlDecode(strKeyValue[0]), string.Empty));
            }

            return colParameters.ToArray();
        }        

        /// <summary>
        /// Get umbraco node from xpath
        /// </summary>
        /// <param name="Path">Path to lookup example /global/setting</param>
        /// <returns></returns>
        public static umbraco.NodeFactory.Node GetNodeFromPath(string Path)
        {
            // Create xpath
            string[] arrpath = Path.Split("/".ToCharArray());
            string strXPath = string.Empty;

            // Build qualified xpath
            for (int intIndex = 0; intIndex < arrpath.Length; intIndex += 1)
            {
                if (intIndex == 0)
                    strXPath = "/root[@id=-1]";
                else
                    strXPath += "/node()[@nodeName=\"" + arrpath[intIndex] + "\"]";
            }

            // Get node from xpath on the instance document
            XmlNode objNode = umbraco.content.Instance.XmlContent.SelectSingleNode(strXPath);
            if (objNode != null)
            {
                string strId = objNode.Attributes["id"].Value;
                return new umbraco.NodeFactory.Node(Convert.ToInt32(strId));
            }

            return new umbraco.NodeFactory.Node(-1);
        }

        /// <summary>
        /// Mask string with pattern
        /// </summary>
        /// <param name="Value">Value to mask</param>
        /// <param name="Length">Amount of visible charaters from the right hand side</param>
        /// <returns>String containing masked value</returns>
        public static string Mask(string Value, int Length)
        {
            if (Value.Length > Length)
            {
                return new string('*', Value.Length - Length) + Value.Substring(Value.Length - Length, Length);
            }

            return Value;
        }
        
        /// <summary>
        /// Validates a credit card number using the standard Luhn/mod10
        /// validation algorithm.
        /// </summary>
        /// <param name="cardNumber">Card number, with or without punctuation</param>
        /// <returns>True if card number appears valid, false if not</returns>        
        public static bool Luhn(string number)
        {
            int[] DELTAS = new int[] { 0, 1, 2, 3, 4, -4, -3, -2, -1, 0 };
            int checksum = 0;
            char[] chars = number.ToCharArray();
            for (int i = chars.Length - 1; i > -1; i--)
            {
                int j = ((int)chars[i]) - 48;
                checksum += j;
                if (((i - chars.Length) % 2) == 0)
                    checksum += DELTAS[j];
            }

            return ((checksum % 10) == 0);
        }

        /// <summary>
        /// Reduce a string size to a length
        /// </summary>
        /// <param name="Value">Value to reduce</param>
        /// <param name="Length">Max length</param>
        /// <returns>Reduced string size</returns>
        public static string Length(string Value, int Length)
        {
            string strValue = Functions.ToStr(Value);

            if (strValue.Length <= Length)
                return strValue;
            else
                return strValue.Substring(0, Length);
        }

        /// <summary>
        /// Convert object to string
        /// </summary>
        /// <param name="Value">Value to convert</param>
        /// <returns>String representation of value</returns>
        public static string ToStr(object Value)
        {
            try
            {
                if (!(Value is DBNull || Value == null))
                {
                    return Convert.ToString(Value);
                }
            }
            catch
            {
                // Error Handler
            }

            return string.Empty;
        }

        /// <summary>
        /// Convert object to int
        /// </summary>
        /// <param name="Value">Value to convert</param>
        /// <returns>Int representation of value</returns>
        public static int ToInt(object Value)
        {
            try
            {
                if (!(Value is DBNull || Value == null))
                {
                    // Try and convert
                    int intValue;
                    if (int.TryParse(Value.ToString(), out intValue) == true)
                    {
                        return intValue;
                    }
                }
            }
            catch
            {
                // Error Handler
            }

            return 0;
        }

        /// <summary>
        /// Get the base url of the site
        /// </summary>
        /// <returns>Base url of the site</returns>
        public static string BaseUrl()
        {
            return HttpContext.Current.Request.Url.Scheme + "://" + HttpContext.Current.Request.Url.Authority + HttpContext.Current.Request.ApplicationPath.TrimEnd('/');
        }

        /// <summary>
        /// Get the base url of the site
        /// </summary>
        /// <returns>Base url of the site</returns>
        public static string BaseUrl(HttpContext Context)
        {
            return Context.Request.Url.Scheme + "://" + Context.Request.Url.Authority + Context.Request.ApplicationPath.TrimEnd('/');
        }

        /// <summary>
        /// Get the current url of the site
        /// </summary>
        /// <returns>Current url of the site</returns>
        public static string CurrentUrl()
        {
            string[] arrUrl = HttpContext.Current.Request.Url.ToString().Split("?".ToCharArray());
            return arrUrl[0];
        }

        /// <summary>
        /// Convert object to money double
        /// </summary>
        /// <param name="Value">Value to convert</param>
        /// <returns>Double money representation of value</returns>
        public static double ToMoney(object Value)
        {
            return ToDbl(ToDbl(Value).ToString("0.00"));
        }

        /// <summary>
        /// Convert object to double
        /// </summary>
        /// <param name="Value">Value to convert</param>
        /// <returns>Double representation of value</returns>
        public static double ToDbl(object Value)
        {
            try
            {
                if (!(Value is DBNull || Value == null))
                {
                    // Try and convert
                    double dblValue;
                    if (double.TryParse(Value.ToString(), out dblValue) == true)
                    {
                        return dblValue;
                    }
                }
            }
            catch
            {
                // Error Handler
            }

            return 0;
        }

        /// <summary>
        /// Convert object to bool
        /// </summary>
        /// <param name="Value">Value to convert</param>
        /// <returns>Bool representation of value</returns>
        public static bool ToBool(object Value)
        {
            try
            {
                if (!(Value is DBNull || Value == null))
                {
                    // Check if the value is a bool
                    if (Value is bool)
                    {
                        return (bool)Value;
                    }
                    // Check if value is string
                    if (Value is string)
                    {
                        // Try converting to bool
                        if (string.Compare((string)Value, "Yes", true) == 0) return true;
                        if (string.Compare((string)Value, "1", true) == 0) return true;
                    }
                    // Check if the value is int
                    if (Value is int)
                    {
                        if (Math.Abs((int)Value) != 0) return true;
                    }

                    // Try and convert
                    bool blnValue;
                    if (bool.TryParse(Value.ToString(), out blnValue) == true)
                    {
                        return blnValue;
                    }
                }
            }
            catch
            {
                // Error Handler
            }

            return false;
        }

        /// <summary>
        /// Convert object to DateTime
        /// </summary>
        /// <param name="value">Value to convert</param>
        /// <returns>DateTime representation of value</returns>
        public static DateTime ToDate(object Value)
        {
            try
            {
                if (!(Value is DBNull || Value == null))
                {
                    if (Value is DateTime)
                    {
                        return (DateTime)Value;
                    }
                    if (IsDate(ToStr(Value)) == true)
                    {
                        // Parse the value
                        return DateTime.Parse(ToStr(Value));
                    }
                }
            }
            catch
            {
                // Error Handler
            }

            return new DateTime(2000, 1, 1);
        }

        /// <summary>
        /// Convert object to TimeSpan
        /// </summary>
        /// <param name="Value">Value to convert</param>
        /// <returns>TimeSpan representation of value</returns>
        public static TimeSpan ToTimeSpan(object Value)
        {
            try
            {
                if (!(Value is DBNull || Value == null))
                {
                    if (Value is TimeSpan)
                    {
                        return (TimeSpan)Value;
                    }

                    // Parse the value
                    return TimeSpan.Parse(ToStr(Value));
                }
            }
            catch
            {
                // Error Handler
            }

            return new TimeSpan();
        }

        /// <summary>
        /// Encode a string to MD5 hash
        /// </summary>
        /// <param name="Value">Value to encode</param>
        /// <returns>MD5 hash representation</returns>
        public static string ToMD5(object Value)
        {
            string strValue = ToStr(Value);
            MD5CryptoServiceProvider objMD5 = new MD5CryptoServiceProvider();
            byte[] bytHash = Encoding.ASCII.GetBytes(strValue);
            // Encode value to hashed MD5
            return Encoding.ASCII.GetString(objMD5.ComputeHash(bytHash));
        }

        /// <summary>
        /// Check if a string is can be converted to datetime
        /// </summary>
        /// <param name="Value">Value to check</param>
        /// <returns>Bool indicating if a string is a DateTime type</returns>
        public static bool IsDate(string Value)
        {
            DateTime dteDate;
            return DateTime.TryParse(Value, out dteDate);
        }

        /// <summary>
        /// Get IPv4 Address from HttpContext connected client
        /// </summary>
        /// <returns></returns>
        public static string GetIPv4Address()
        {
            try
            {
                foreach (IPAddress IPA in Dns.GetHostAddresses(HttpContext.Current.Request.UserHostAddress))
                {
                    // Check if the address type is a standard InterNetwork IPv4
                    if (IPA.AddressFamily.ToString() == "InterNetwork")
                    {
                        return IPA.ToString();
                    }
                }
            }
            catch
            {
            }

            return string.Empty;
        }

        /// <summary>
        /// Get IPv4 Address from HttpContext connected client
        /// </summary>
        /// <returns></returns>
        public static string GetIPv4Address(HttpContext Context)
        {
            try
            {
                foreach (IPAddress IPA in Dns.GetHostAddresses(Context.Request.UserHostAddress))
                {
                    // Check if the address type is a standard InterNetwork IPv4
                    if (IPA.AddressFamily.ToString() == "InterNetwork")
                    {
                        return IPA.ToString();
                    }
                }
            }
            catch
            {
            }

            return string.Empty;
        }

        /// <summary>
        ///  Get configuration setting from app.settings
        /// </summary>
        /// <param name="Key">Setting to get</param>
        /// <returns>Setting value</returns>
        public static string GetSetting(string Key)
        {
            try
            {
                return Functions.ToStr(System.Configuration.ConfigurationManager.AppSettings[Key]);
            }
            catch
            {
                // Setting not found
            }

            return string.Empty;
        }

        /// <summary>
        /// Check if a value is dbnull or null
        /// </summary>
        /// <param name="Value">Value to check</param>
        /// <returns>Bool indicating if a value is dbnull or null</returns>
        public static bool IsDBNull(object Value)
        {
            if (!(Value is DBNull || Value == null))
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        /// <summary>
        /// Check if a value is a representation of a Guid
        /// </summary>
        /// <param name="Value">Value to check</param>
        /// <returns>Bool indicating if a value is a Guid</returns>
        public static Boolean IsGuid(string Value)
        {

            // this is before the overhead of setting up the try/catch block.
            if (Value.Length == 32 ||
                Value.Length == 36 ||
                Value.Length == 38 ||
                Value.Length == 40)
            {
                try
                {
                    Guid strValue = new Guid(Value);
                    return true;
                }
                catch (FormatException)
                {
                    return false;
                }
            }

            return false;
        }

        /// <summary>
        /// Convert DateTime to a more eye friendly string
        /// </summary>
        /// <param name="Value">DateTime to convert</param>
        /// <returns>Friendly datetime string representation</returns>
        public static string FormatDate(DateTime Value)
        {
            if (Value.Date == DateTime.Now.Date)
            {
                return "Today " + Value.ToString("HH:mm");
            }
            else if (Value.Date == DateTime.Now.Date.AddDays(-1))
            {
                return "Yesterday " + Value.ToString("HH:mm");
            }
            else
            {
                return Value.ToString("dd/MM/yy HH:mm");
            }
        }

        /// <summary>
        /// Calculate the VAT amount for a value
        /// </summary>
        /// <param name="Value">Value to calculate</param>
        /// <param name="VATRate">Rate of VAT e.g. 20% = 0.2</param>
        /// <param name="Inclusive">Is the VAT inclusive of the value</param>
        /// <returns></returns>
        public static double CalculateVAT(double Value, double VATRate, bool Inclusive)
        {
            if (Inclusive && VATRate != 0)
                return Functions.ToMoney(Value - (Value / (1 + VATRate)));
            else if (Inclusive && VATRate == 0)
                return Functions.ToMoney(Value);
            else
                return Functions.ToMoney(Value * VATRate);
        }

        /// <summary>
        /// Add to string within postfix or prefix
        /// </summary>
        /// <param name="Value"></param>
        /// <param name="Add"></param>
        /// <param name="Prefix"></param>
        /// <param name="Postfix"></param>
        /// <returns></returns>
        public static string AddToString(string Value, string Add, string Prefix, string Postfix)
        {
            if (Value.Length != 0 &&
                Add.Length != 0)
                return Value + Prefix + Add + Postfix;
            else if (Add.Length != 0)
                return Add;
            else
                return Value;
        }

    }

}
